📜 ⬆️ ⬇️

Answers to questions with PyObject

Hello. In this article I will try to answer questions and tasks on Python from the site pyobject.ru, as well as explain why I did it. The questions themselves are available here .

Disclaimer :
I warn you immediately: the post is written by a noob in python and programming in general. If you have clarifications and comments (and I hope they will), please write.


Answers will be broken down into the same categories as questions.
PS Python I have version 2.6.6

So, let's begin.
')

Types of data, basic constructions


For convenience, we will create a small test class:
class Foo(object): """docstring for Foo""" arg1 = None _arg2 = None __arg3 = None def __init__(self): super(Foo, self).__init__() def bar(self): pass 


1. How to get a list of all object attributes
  print dir(Foo) 


2. How to get a list of all public attributes of an object
In Python, to denote the protected attributes use "_", for private - "__" before the variable name. Therefore, to get a list of public attributes only, the list of all attributes must be filtered. This can be done either with the help of list comprehension:
  print [arg for arg in dir(Foo) if not arg.startswith('_')] 

or use the filter function:
  print filter(lambda x: not x.startswith('_'), dir(Foo)) 

As for me, the first option is preferable because of the greater readability.

3. How to get a list of object methods
Since functions and methods in Python are objects of the first kind (it seems to have written correctly?), We’ll use the getattr function, which returns the object attribute itself and the callable function, which performs the validation.
  print [arg for arg in dir(Foo) if callable(getattr(Foo, arg))] #  print filter(lambda arg: callable(getattr(Foo, arg)), dir(Foo)) 


4. In what “magic” variable is help content stored?
In the __doc__ attribute. A comment is entered into this variable immediately after
class / method / function declarations (see test class).

  print Foo.__doc__ 

You can also use the help function online:
  >>> help(int) 


5. There are two tuples, get the third as the concatenation of the first two
  print (2, 5) + (4, 6) 


6. There are two tuples, get the third as the union of the unique elements of the first two tuples
In this assignment, I saw 2 approaches:
1. write loops to check the entry of an element in tuples
2. use the built-in type set (essentially a hash), on which you can apply logical operations.
Solution using the second approach (using XOR):
  print tuple(set((2, 3, 4)) ^ set((4, 5))) 


7. Why if the list is changed in a loop, then for x in lst [:] is used, what does [:] mean?
[:] - the designation of the cut in python. About them you can read, for example, here . In short: [:] creates a copy of lst and the changes in the first do not affect the iteration over the original values.

8. There are two lists of the same length, in one key, in another value. Compile a dictionary.
We will use the zip function, which makes tuples from a pair of values ​​and dict, which creates a dictionary from the passed arguments.
  a = ('John', 'Peter') b = (1, 2) print dict(zip(a, b)) 


9. There are two lists of different lengths, in one key, in another value. Compile a dictionary. For keys for which there is no value, use None as the value. Values ​​for which there are no keys to ignore.
  a = ('John', 'Peter', 'Daniel') b = (1, 2) print dict((len(a) > len(b)) and map(None, a, b) or zip(a, b)) #    if/else,   Python 2.5 print dict(map(None, a, b) if (len(a) > len(b)) else zip(a, b)) 

In this case, we will use the functions zip, map. A special feature of zip is that the returned result is limited to the shortest iterated. That is, it is perfect for us in the case when there are more values ​​than keys. In the second branch of python, map has one documented feature, namely, if any of the iterated values ​​is shorter than the others, it is supplemented with None. If None is passed instead of the function, the union is performed and we get the same tuples at the output.
Alternatively, you can consider using the function itertools.izip_longest, which was added in 2.6.

10. There is a dictionary. Invert it. Those. pairs of key: value swap - value: key.
  a = {'John': 1, 'Peter': 2} print dict((val, key) for (key, val) in a.iteritems()) 

Alternatively, use the zip function again.
  a = {'John': 1, 'Peter': 2} print dict(zip(a.itervalues(), a.iterkeys())) 

PS I ask the guru to suggest that it is more appropriate to use in this case - zip or itertools.izip. The same applies to values ​​/ itervalues.

11. There is a string in Unicode, get an 8-bit utf-8 and cp1251 string
I wrote right at the time of writing this article, but if I understood the task correctly, then:
  greeting = u'' print greeting.encode('utf-8') print greeting.encode('cp1251') 


12. There is a string encoded in cp1251, get a unicode string
Similarly:
  greeting = '' print greeting.decode('cp1251') 


Functions


1. Write a function to which you can pass arguments either by a list / tuple, or one by one. The function summarizes all the arguments.
I see the solution as follows: iteration over the transferred list. If the list element has the attribute __len__, which means it is iterable, expand it and pass it to our function.
  def sum(*args): """ Returns sum of the args. >>> sum(1) 1 >>> sum(2, 2) 4 >>> sum(1, 2, (3, 4)) 10 >>> sum(1, ()) 1 >>> sum(-1, 1.0) 0.0 """ result = 0 for arg in args: if hasattr(arg, '__len__'): result += sum(*arg) else: result += arg return result 


2. Write a factory function that will return an addition function with an argument.
Since functions are objects of the first kind (if you mess them up, so big), then one of the options for using them is to return them from other functions or methods and pass them on as arguments. The bottom line is that we have to return the addition function, one of the arguments
which is set at its creation, and the second can vary. As I understand it, this is a closure - access to variables declared outside the function body.
  def addition_inner(val): """ >>> add5 = addition_inner(5) >>> add5(3) 8 >>> add1 = addition_inner(-1) >>> add1(3) 2 >>> add_str = addition_inner('s') >>> add_str(3) Traceback (most recent call last): ... TypeError: unsupported operand type(s) for +: 'int' and 'str' """ def func(arg): return arg + val return func def addition_lambda(val): """ >>> add5 = addition_lambda(5) >>> add5(3) 8 >>> add1 = addition_lambda(-1) >>> add1(3) 2 >>> add_str = addition_lambda('s') >>> add_str(3) Traceback (most recent call last): ... TypeError: unsupported operand type(s) for +: 'int' and 'str' """ return lambda x: x + val 


3. Write a factory similar to item 2, but returning a list of such functions.
In this case, it makes sense to return the list of functions that we wrote above.
It will look something like this:
  def additions(start, end): """ Returns list of addition functions >>> for addition in additions(0, 5): ... print addition(1) 1 2 3 4 5 >>> print additions(5, 0) [] >>> print additions(0, 2) # doctest: +ELLIPSIS [<function func at 0x...>, <function func at 0x...>] """ return [addition_inner(val) for val in range(start, end)] 

4. Write an analogue map:
- the first argument is either a function or a list of functions
- the second argument is the list of arguments that will be passed to the functions
- it is assumed that these functions are functions of one argument
I implemented this task using the built-in map (alternatively, it was replaced by a cycle). Also, to check the type of the passed value, I used the isinstance function and the collections module, as an analogue of hasattr and the __len__ magic method.
  def mymap(func, args): """ Applies list of functions for args. >>> add0 = addition_inner(0) >>> add1 = addition_inner(1) >>> add2 = addition_inner(2) >>> add5 = addition_inner(5) >>> print mymap(add5, [1, 2, 3]) [6, 7, 8] >>> print mymap([add0, add1, add2], [1, 2, 3]) [(1, 2, 3), (2, 3, 4), (3, 4, 5)] >>> print mymap([], []) [] >>> print mymap(sum, [(3, 4, 5, 6, (7,))]) [25] """ if isinstance(func, collections.Iterable): return [tuple(map(f, args)) for f in func] #  #return [tuple(f(arg) for arg in args) for f in func] else: return [func(arg) for arg in args] 


Iterators


A small retreat. I did not see much point in writing iterator code, since their code is described in the documentation for the itertools module. Hardly I will write better.
Iterators are based on generators, which is a great article .

Modules


1. We have an imported module foo, how to find out the physical path of the file, where it is imported from?
The path is stored in the __file__ attribute of the module.

2. From the foo module you import the feedparser module. The X feedparser version is in the system-wide site-packages directory, version Y is next to the foo module. The environment variable PYTHONPATH is defined, and there is also a feedparser, version Z. What version will be used?
Version Y will be imported.
According to the documentation (section 6 of the tutorial), the import procedure is as follows:
1. directory next to the script that was running
2. PYTHONPATH
3. system catalog

3. How to view a list of directories in which Python is looking for modules?
  >>> import sys >>> sys.path 


4. You have a foo module, inside it a bar module is imported. Next to the foo module there are files bar.py and bar / __ init__.py Which module will be used.
The second will be used, i.e. package. As I understand it, a recursive directory traversal occurs, and the packages are imported first.

5. What does the construction __name__ == '__main__' mean and what is it used for?
Used to determine whether a file has been imported or launched. If we run it, the value will be __main__; if we import it, the name of the module.

Today is all, thank you.
PS If anyone is interested, I will write my version of the answers to the last 2 sections.

Source: https://habr.com/ru/post/145369/


All Articles