I've been learning python for a while now but I really want to start using oop but I'm having trouble understanding it, please can you tell me where I'm going wrong with my class.
class Savecookies():
driver = webdriver.Firefox()
def __init__(self, site, url):
self.site = site
self.url = url
def twitter(driver, self.site, self.url):
if __name__=='__main__':
cooks = Savecookies('twitter', 'https://twitter.com/')
My error:
File "twitter_test2.py", line 26
def twitter(driver, self.site, self.url):
^
SyntaxError: invalid syntax
def twitter(driver, self.site, self.url):
What’s that?
First of all, methods need a body. Otherwise they are incomplete. The simplest body would be to just do pass (i.e. do nothing). But you probably want to add actual stuff in there.
Second, your arguments make no sense at all. The first argument of a method is self, and then you specify which other arguments you want the method to accept. And argument names need to be valid variables, so you cannot have a dot in there. And if you want the method to access self.site and self.url, you can just do that without needing to pass it to the function (since you have access to self). In your case, you already have the site and url from the Savecookies object, so you probably want something like this:
def twitter(self, driver):
# Do something useful here
print(self.site, self.url)
print(driver)
in case twitter is an instance method
change
def twitter(driver, self.site, self.url):
to
def twitter(self):
#now do something with the params
print(self.driver, self.site, self.url)
Basically, let it access the site and url instance attributes set by __init__
and let it access the driver class attribute set in the class
Both types of attributes can be reached through self., there is no need to pass it again as a parameter.
Related
I am trying to create a class which takes a URL and allows me to split it into parts and return each of the scheme, server, and path.
class SimpleURL:
def __init__(self,url):
self.url=url
def scheme(self):
return url.split("://")[0]
def server(self):
return url.split("/")[2]
def path(self):
return url.split(url.split("/")[2])[1]
test_url = SimpleURL("https://gumgoose.com/larry/friendo")
Then, if I run
test_url.scheme()
or any server or path, I get the error
NameError: name 'url' is not defined
I am able to make it work if I assign the url to the variable "url" outside of the function, but to my understanding, the line beginning "test_url" should be doing that for me.
Can anybody shed some light onto this for me?
Within all of your class methods, you will need to explicitly use self to refer to all other class methods and attributes.
def scheme(self):
return self.url.split('://')[0]
If you do not do this, Python will only search the local scope within your method and the global scope. That is why if you define url outside of your class, you don't have any issues.
Python requires you reference the instance object too i.e.
return self.url.split('://')[0]
So I am working with an API wrapper in python for vk, Europe's Facebook equivalent. The documentation on the vk site has all the API calls that can be used, and the wrapper is able to call them correctly. For example, to get a user's information, you would call api.users.get(id) to get a user by id. My question is this: how can the wrapper correctly handle such a call when neither users or a corresponding users.get() method is defined inside the api object?
I know it involves the __getattr__() and __call__() methods, but I can't find any good documentation on how to use them in this way.
EDIT
the api object is instantiated via api = vk.API(id, email, password)
Let's walk through this together, shall we?
api
To execute api.users.get(), Python first has to know api. And due to your instantiation, it does know it: It's a local variable holding an instance of APISession.
api.users
Then, it has to know api.users. Python first looks at the members of the api instance, at the members of its class (APISession) and at the members of that class' super-classes (only object in the case of APISession). Failing to find a member called users in any of these places, it looks for a member function called __getattr__ in those same places. It will find it right on the instance, because APISession has an (instance) member function of this name.
Python then calls it with 'users' (the name of the so-far missing member) and uses the function's return value as if it were that member. So
api.users
is equivalent to
api.__getattr__('users')
Let's see what that returns.
def __getattr__(self, method_name):
return APIMethod(self, method_name)
Oh. So
api.users # via api.__getattr__('users')
is equivalent to
APIMethod(api, 'users')
creating a new APIMethod instance.
api and 'users' end up as that instance's _api_session and _method_name members. Makes sense, I guess.
api.users.get
Python still hasn't executed our statement. It needs to know api.users.get() to do so. The same game as before repeats, just in the api.users object instead of the api object this time: No member method get() and no member get is found on the APIMethod instance api.users points to, nor on its class or superclasses, so Python turns to the __getattr__ method, which for this class does something peculiar:
def __getattr__(self, method_name):
return APIMethod(self._api_session, self._method_name + '.' + method_name)
A new instance of the same class! Let's plug in the instance members of api.users, and
api.users.get
becomes equivalent to
APIMethod(api, 'users' + '.' + 'get')
So we will have the api object also in api.user.get's _apisession and the string 'users.get' in its _method_name.
api.users.get() (note the ())
So api.users.get is an object. To call it, Python has to pretend it's a function, or more specifically, a method of api.users. It does so, by instead calling api.users.get's __call__ method, which looks like this:
def __call__(self, **method_kwargs):
return self._api_session(self._method_name, **method_kwargs)
Let's work this out:
api.users.get()
# is equivalent to
api.users.get.__call__() # no arguments, because we passed none to `get()`
# will return
api.users.get._api_session(api.users.get._method_name)
# which is
api('users.get')
So now Python is calling the api object as if it were a function. __call__ to the rescue, once more, this time looking like this:
def __call__(self, method_name, **method_kwargs):
response = self.method_request(method_name, **method_kwargs)
response.raise_for_status()
# there are may be 2 dicts in 1 json
# for example: {'error': ...}{'response': ...}
errors = []
error_codes = []
for data in json_iter_parse(response.text):
if 'error' in data:
error_data = data['error']
if error_data['error_code'] == CAPTCHA_IS_NEEDED:
return self.captcha_is_needed(error_data, method_name, **method_kwargs)
error_codes.append(error_data['error_code'])
errors.append(error_data)
if 'response' in data:
for error in errors:
warnings.warn(str(error))
return data['response']
if AUTHORIZATION_FAILED in error_codes: # invalid access token
self.access_token = None
self.get_access_token()
return self(method_name, **method_kwargs)
else:
raise VkAPIMethodError(errors[0])
Now, that's a lot of error handling. For this analysis, I'm only interested in the happy path. I'm only interested in the happy path's result (and how we got there). So lets start at the result.
return data['response']
Where did data come from? It's the first element of response.text interpreted as JSON that does contain a 'response' object. So it seems that from the response object we got, we're extracting the actual response part.
Where did the response object come from? It was returned by
api.method_request('users.get')
Which, for all we care, is a plain normal method call that doesn't require any fancy fallbacks. (Its implementation of course, on some levels, might.)
Assuming the comments are correct, and api is an instance of APISession as defined in this particular commit, then this is a bit of an interesting maze:
So first you want to access api.user. APISession has no such attribute, so it calls __getattr__('user') instead, which is defined as:
def __getattr__(self, method_name):
return APIMethod(self, method_name)
So this constructs an APIMethod(api,'user'). Now you want to call the method get on the APIMethod(api,'user') that is bound to api.users, but an APIMethod doesn't have a get method, so it calls its own __getattr__('get') to figure out what to do:
def __getattr__(self, method_name):
return APIMethod(self._api_session, self._method_name + '.' + method_name)
This returns a APIMethod(api,'users.get') which is then called, invoking the __call__ method of the APIMethod class, which is:
def __call__(self, **method_kwargs):
return self._api_session(self._method_name, **method_kwargs)
So this tries to return api('users.get'), but api is an APISession object, so it invokes the __call__ method of this class, defined as (stripping out the error handling for simplicity):
def __call__(self, method_name, **method_kwargs):
response = self.method_request(method_name, **method_kwargs)
response.raise_for_status()
for data in json_iter_parse(response.text):
if 'response' in data:
return data['response']
So it then calls a method_request('users.get'), which if you follow that method actually does a POST request, and some data comes back as a response, which is then returned.
The users.get() has nothing to do with the api object. As for the users, you are right, if there is no such member defined, then there is certainly some logic inside the __getattr__. So as you can see in the documentation __getattr__ is...
Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self). name is the attribute name.
So exactly, as there is no users defined for the api's class, then the __getattr__ is being called with 'users' passed as the name parameter. Then, most probably dynamically, depending on the passed parameter, an object is being constructed for the users component and returned, which will be responsible to define or handle in similar way the get() method.
To get the whole idea, try the following:
class A(object):
def __init__(self):
super(A, self).__init__()
self.defined_one = 'I am defined inside A'
def __getattr__(self, item):
print('getting attribute {}'.format(item))
return 'I am ' + item
a = A()
>>> print(a.some_item) # this will call __getattr__ as some_item is not defined
getting attribute some_item
I am some_item
>>> print(a.and_another_one) # this will call __getattr__ as and_another_one is not defined
getting attribute and_another_one
I am and_another_one
>>> print(a.defined_one) # this will NOT call __getattr__ as defined_one is defined in A
I am defined inside A
I need to call a function method complete_login:
class VKOAuth2Adapter(OAuth2Adapter):
...
def complete_login(self, request, app, token, **kwargs):
...
It should be really easy, but i cant understand what parameter should be send in "self". I know why its there, but how to call such method?
login = VKOAuth2Adapter.complete_login( ??? , request, app, token)
Thanks.
You need to make an instance of the class:
v = VKOAuth2Adapter( whatever parameters it needs, if any )
and then you'll call:
v.complete_login(request, app, token)
where v will automatically become the method's self.
The self parameter is usually not passed explicitly when calling a Python method--it is implicit. So you'd do this:
vk = VKOAuth2Adapter()
vk.complete_login(req, app, token)
The vk instance will be passed as self. You could write the code this way too:
vk = VKOAuth2Adapter()
VKOAuth2Adapter.complete_login(vk, req, app, token)
But that would not be considered normal practice in Python, so use the first option.
Note that if you are calling the method from inside another method in the same class, you'd do it this way:
self.complete_login(req, app, token)
That's because self would be an instance of the class, just as vk was in my previous examples.
I'm attempting to call test_check_footer_visible in another .py file.
origin.py has:
class FooterSection(unittest.TestCase):
"""
"""
browser = None
site_url = None
def setUp(self):
self.browser.open(self.site_url)
self.browser.window_maximize()
# make footer section
self._footer = FooterPage(self.browser)
def test_check_footer_visible(self):
#press the page down
self.browser.key_down_native("34")
self.browser.key_down_native("34")
self.browser.key_down_native("34")
print "Page down"
time.sleep (10)
Now in dest.py I need to call test_check_footer_visible(). How do I do that?
dest.py has the following format:
class TestPageErrorSection(unittest.TestCase):
"""
"""
browser = None
site_url = None
def setUp(self):
global SITE_URL, BROWSER
if not BROWSER:
BROWSER = self.browser
if not SITE_URL:
SITE_URL = self.site_url
BROWSER.open(SITE_URL)
BROWSER.window_maximize()
print 'page not found 404 error'
self._pageerror_section = ErrorSection(BROWSER)
def _primary_navigation(self):
# I want to call test_check_footer_visible here.
I tried everything in Call Class Method From Another Class
You can't (without doing some really shady things -- see comments by #glglgl) -- at least not without changing your code somewhat. The reason you can't is because test_check_footer_visible will assert that the first element passed in is an instance of the class FooterSection (which it isn't -- it's an instance of TestPageErrorSection). You have (at least) a couple of options for the re-factor.
1) Make TestPageErrorSection inherit from FooterSection and use that function directly (e.g. self.test_check_footer_visible() This doesn't seem like a very good option to me based on the class names
2) Make test_check_footer_visible() a regular function. It can then be called from either class.
3) Create a 3rd class (e.g. SectionBase), put test_check_footer_visible on that class and have your other 2 classes inherit from it.
I'm implementing a python application which is using ThreadingTCPServer and a custom subclass of BaseRequestHandler. The problem with this is that the ThreadingTCPServer seems to automatically spawn threads and create instances of the handler, calling their handle() function. However this leaves me with no way to pass data to the handler other than using global variables or class variables, both of which seem hackish. Is there any better way to do it?
Ideally this should be something like:
class ThreadedTCPServer(ThreadingTCPServer):
def process_request(self, *args, **kwargs):
ThreadingTCPServer.process_request(self, data, *args, **kwargs)
with the handler like
class ThreadedTCPRequestHandler(BaseRequestHandler):
def handle(self,data):
#do something with data
I stumbled upon the very same thing. My solution was the following:
class ThreadedTCPRequestHandler(SocketServer.StreamRequestHandler):
def handle(self):
print(self.server.mycustomdata)
class ThreadedTCPServer(SocketServer.ThreadingTCPServer):
pass
server = ThreadedTCPServer((args.host, args.port), ThreadedTCPRequestHandler)
server.mycustomdata = 'foo.bar.z'
server.serve_forever()
The RequestHandler is called with a server object as a third parameter, and it is saved as self.server attribute, so you can access it. If you would set this attribute to a callable, you could easily call it, too:
def handle(self):
mycustomdata = self.server.mycustomdata()
The first answer worked for me, but I think it is cleaner to alter the __init__ method and pass the attribute in the constructor:
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
def __init__(self, host_port_tuple, streamhandler, Controllers):
super().__init__(host_port_tuple, streamhandler)
self.Controllers = Controllers
Note the third parameter 'Controllers' in the constructor, then the call to super without that parameter, then setting the new attribute Controllers to the property self.Controllers. The rest of the class is unchanged. Then, in your Requesthandler, you get access to the parameter using the 'server' attribute, as described above:
def handle(self):
self.Controllers = self.server.Controllers
<rest of your code>
It's much the same as the answer above but I find it a little cleaner because the constructor is overloaded and you simply add the attribute you want in the constructor:
server = ServerInterface.ThreadedTCPServer((HOST, PORT), ServerInterface.ThreadedTCPRequestHandler, Controllers)
Since handle is implemented by your BaseRequest subclass, it can get the data from itself without having it passed by the caller. (handle could also be a callable attribute of the request instance, such as a lambda—explicit user_data arguments are normally unnecessary in idiomatically designed python.)
Looking at the SocketServer code, it should be straightforward to override finish_request to pass the additional data to your BaseRequestHandler subtype constructor which would store it in the instance for handle to use.