I wrote variables in init's brackets, which should be default if I don’t enter anything, but I get an error if I don’t enter anything and python don’t see the default values for the variables. I am using there input to understand the user what to enter and I would like to leave it.
class News:
def __init__(self, content='Test NEWS name', city='None', news_date_and_time='Not defined'):
self.content = str(input('Write down news content:'))
self.city = str(input('Write down news CITY:'))
self.news_date_and_time = datetime.now().strftime("%d/%m/%Y %H:%M")
pub = News()
I can achieve the input by passing it to the function, as I wrote below, but I want the function use an input and default values which are written
class News:
def __init__(self, content='Test NEWS name', city='None', news_date_and_time='Not defined'):
self.content = content
self.city = city
self.news_date_and_time = datetime.now().strftime("%d/%m/%Y %H:%M")
pub = News('dog ate potatoes','New York')
pub = News(str(input('Input the content:')), str(input('Input the city:')))
How can I implement in the function an input of the variables and the default values are which are written in the function if the wasn't written anything?
but I want the function use an input and default values which are written
This violates the Single Responsibility Principle. Typically we design classes to take arguments similar to how you show in the second code example. This allows the flexibility of reuse because the class doesn't care where the value comes from. In your current situation, you get the values from user input, but you can easily create News objects from database values instead, for example.
To implement default values, I suggest building a separate class or function that decides whether to get input or to use default values. This will make your code in line with the Seperation of Concerns principle.
This function will work the way you want it to work if you test the value of input() and assign the parameter if it's empty:
class News:
def __init__(self, content='Test NEWS name', city='None', news_date_and_time='Not defined'):
self.content = input('Write down news content:') or content
self.city = input('Write down news CITY:') or city
self.news_date_and_time = datetime.now().strftime("%d/%m/%Y %H:%M")
As noted, though, this is bad design, because now it's impossible to create a News object without having it stop your script to ask for input. You should instead do this outside of the constructor:
class News:
def __init__(self, content, city):
self.content = content
self.city = city
self.news_date_and_time = datetime.now().strftime("%d/%m/%Y %H:%M")
pub1 = News("Dog ate potatoes", "New York")
pub2 = News(input("Enter content: "), input("Enter city: "))
Note that there's no reason to have a news_date_and_time parameter since you always use datetime.now in your constructor.
Related
New to OOP and python, I am struggling enormously to grasp what good classes actually are for. I tried to ask help from a lecturer who said "oh, then you should read about general methods to classes". Been putting in a days work but get no where.
I get it that a class allow you to collect an instance structure and methods to it, like this:
class Items:
def __init__(self, item_id, item_name):
self.item_id = item_id
self.item_name = item_name
def show_list(self):
print(self.item_id, self.item_name)
idA = Items("idA", "A")
idA.show_list()
But what is even the point of a class if there were not MANY instances you would classify? If I have a method within the class, I must hard code the actual instance to call the class for. What if you want a user to search and select an instance, to then do operations to (e.g. print, compute or whatever)??
I thought of doing it like this:
class Items:
def __init__(self, item_id, item_name):
self.item_id = item_id
self.item_name = item_name
def show_list(self):
print(self.item_id, self.item_name)
idA = Items("idA", "A")
idB = Items("idB", "B")
select_item = input("enter item id")
select_item.show_list()
Replacing hard coded variable with input variable doesn't work, probably logically. I then played with the idea of doing it like this:
class Items:
def __init__(self, item_id, item_name):
self.item_id = item_id
self.item_name = item_name
iL = [Items('idA', 'A'), Items('idB', 'B')]
selected_item = input("enter item id")
for selected_item in iL:
print(f'{selected_item.item_id} {selected_item.item_name}')
Now all are called thanks to making it a list instead of separate instances, but how do I actually apply code to filter and only use one instance in the list (dynamically, based on input)?
I would love the one who brought me sense to classes. You guys who work interactively with large data sets must do something what I today believe exist in another dimension.
See examples above^^
It seems you want to find all the instances of a certain element within a class.
This is as simple as:
print([x for x in iL if x.item_id == selected_item])
Now, you may ask why you can't just store the elements of iL as tuples instead of classes. The answer is, you can, but
("idA", "A")
is much less descriptive than:
item_id = "idA"
item_name = "A"
Any code you write with classes, you should in theory be able to write without classes. Classes are for the benefit of the coder, not the end-user of the program. They serve to make the program more readable, which I'm sure you'll find is a desirable property.
Your point here is to lookup for Items instances based on their item_id attribute.
That's a thing to create instances of a class.
It's a completely different thing to search for items objects stored in memory - that is not directly linked to the concept of OOP, classes and instances.
You could use dictionary to store references of your objects and then lookup in your dictionary.
class Items:
def __init__(self, item_id, item_name):
self.item_id = item_id
self.item_name = item_name
def show_list(self):
print(self.item_id, self.item_name)
idA = Items("idA", "A")
idB = Items("idB", "B")
lookup_dict = {"idA": idA, "idB": idB}
select_item = input("enter item id")
found_item = lookup_dict.get(select_item)
if found_item:
found_item.show_list()
else:
print(f"item {select_item} not found")
I'm new to Python and I'm working on a crawler project.
I have a case want to ask you about good way to handle.
For example.
class Student:
def __init__(
self,
user_id: str,
name: str = None,
age: int = None,
gender: str = None
):
self.name = name
self.age = age
self.gender = gender
user_id = "test_user_id"
# after crawling data by selenium/scrapy
# we have 2 types to build/update class property
# STYLE 1:
student = Student(user_id)
student.name = "AAAA"
student.age = "18"
student.gender = "male"
# STYLE 2:
name = "AAAA"
age = "18"
gender = "male"
student = Student(
user_id=user_id,
name=name,
age=age,
gender=gender)
About the #STYLE 1, I'm not really it's a good way or not. But about #STYLE 2 I think it's gonna have some problem because we have to define a lot of variables (hard to debug), and we have to guarantee the variables have to be initialized before create class instance.
That's my question, please give me your guys idea about this or which way do you guy prefer.
I'm afraid this question will be closed soon as it requires opinion based answers, and is probably out of scope here. Nevertheless it raises an interesting point, so I will give my two cents.
If you are talking about properties that you will set at once, on creation or immediately after, I would definitely go with the second approach. As Punit said in a comment, you can (and usually will) directly pass the values, without creating intermediate variables unless they are already there. And if some of the properties are really necessary to work with the instance, I would avoid specifying a default value, thus making them required.
This way the instance creation is IMO both more readable and more reliable. And if you have really many arguments, you can require that most or all are passed as kwargs, which will further improve readability.
Then you may sometimes have other properties which are not needed, or may be even unknown, at creation time - and of course those will be set later, with the first style.
The best to go about this is to have all this code compressed into a smaller block. This helps make the code look more concise. Also, you forgot to set user_id in STYLE #1.
class Student:
def __init__(self, id: int, name: str, age: int, gender: str):
self.id = id
self.name = name
self.age = age
self.gender = gender
data = [] #scraped data from target site
# assuming a user instance looks like this: { name, age, id, gender }
# using list comprehensions to make it look cool
# you can replace the arguments in `Student()` with whatever fits the
# response from target site
users = [Student(i.id, i.name, i.age, i.gender) for i in data]
Hope this helps!
I would distinguish 2 cases here: Creation of the instance and update.
In the first case you can directly assign the values to the constructor of the class.
classStudent:
def __init__(self, user_id: str, name: str = None, age: int = None, gender: str = None):
self.user_id = user_id # You forgot this attribute!
self.name = name
self.age = age
self.gender = gender
student = Student(
# All the values you have available like you do in STYLE 2
)
In the case of updating it would be easier without using the variables and assigning them directly. Hard to debug, as you said.
student.name = "YYYY"
student.age = "18"
student.gender = "male"
There is nothing wrong in doing this in Python as you don't have to make getters and setters like other languages.
Even so, it would be recommended that you add conditionals to check if the values are valid before making the modification.
This question already has answers here:
__str__ returned non-string (type tuple)
(3 answers)
Closed 4 years ago.
I'm still very new to Python, and am struggling with what should be a simple assignment. I have to write code for an 'Employee' class, save the module, import the module into another .py file and then store and display 3 objects of that class. I keep getting a
"TypeError: __str__ returned non-string (type tuple)"
no matter how I rework the code, and it's driving me nuts. Anything I've done wrong, please, explain to me how/why it's wrong, learning this is incredibly important to me!
The following is the code for the Employee class:
class Employee:
def __init__(self,name,id,dept,title):
self.__name = name
self.__id = id
self.__dept = dept
self.__title = title
def set_name(self,name):
self.__name = name
def set_id(self,id):
self.__id = id
def set_dept(self,dept):
self.__dept = dept
def set_title(self,title):
self.__title = title
def get_name(self):
return self.__name
def get_id(self):
return self.__id
def get_dept(self):
return self.__dept
def get_title(self):
return self.__title
def __str__(self):
return 'Name: ',self.__name,'\n','ID Number: ',str(self.__id),'\n','Department: ',self.__dept,'\n','Job Title: ',self.__title
I'm not sure I need the set and/or get name methods, because the three objects I have to store and display are pre-determined (no user input or anything). The preceding code is saved in a file named emp.py. The following code is where I think the problem is, but being a novice I don't know for sure.
import emp
def main():
name = 'Susan Meyers'
id = '47899'
dept = 'Accounting'
title = 'Vice President'
employee1 = emp.Employee(name,id,dept,title)
name = 'Mark Jones'
id = '39119'
dept = 'IT'
title = 'Programmer'
employee2 = emp.Employee(name,id,dept,title)
name = 'Joy Rogers'
id = '81774'
dept = 'Manufacturing'
title = 'Engineer'
employee3 = emp.Employee(name,id,dept,title)
print('Employee 1:')
print(employee1)
print('Employee 2:')
print(employee2)
print('Employee 3: ')
print(employee3)
main()
I've tried this by creating an object (i.e. susan = emp.Employee['Susan',id number,'dept','title'] with the appropriate information where id, dept, title are, but still get the tuple error. What am I doing wrong? I considered storing the information in a list or dictionary, but figured I should stick to the bare-bones basics. I feel so stupid, I've been at this all day! For any and all help, thanks in advance.
EDIT: Fixed the indention errors (weren't present in my code in pycharm, but copying and pasting them here w/o proper proofreading...)
FURTHER EDIT:
When run, I need it to say:
Employee 1:
Name: Susan Meyers
ID Number: 47899
Department: Accounting
Title: Vice President
Employee 2:
Name: Mark Jones
ID Number: 39119
Department: IT
Title: Programmer
Employee 3:
Name: Joy Rogers
ID Number: 81774
Department: Manufacturing
Title: Engineer
**And that's the end of the program, like I said, should be really basic stuff, if this were a list or something, I could knock it out np... But each employee has to be stored as an object of the Employee class. We just covered an incredibly long chapter on Classes and Objects (while I was sick with the flu) so my recall/methods may not be the best.
The error's with the __str__ method itself
def __str__(self):
return 'Name: ',self.__name,'\n','ID Number: ',str(self.__id),'\n','Department: ',self.__dept,'\n','Job Title: ',self.__title
"TypeError: __str__ returned non-string (type tuple)"
This error notifies you that
'Name: ',self.__name,'\n','ID Number: ',str(self.__id),'\n','Department: ',self.__dept,'\n','Job Title: ',self.__title
is a tuple. (This is implicitly constructed from the comma-delimited notation.) However, Python is expecting a str as the return type. Change your return statement so that it returns a string. You can use
return ''.join(['Name: ',self.__name,'\n','ID Number: ',str(self.__id),'\n','Department: ',self.__dept,'\n','Job Title: ',self.__title])
or
return 'Name: {}\nID Number: {}\nDepartment: {}\nJob Title: {}'.format(self.__name, self.__id, self.__dept, self.__title)
or anything as long as it returns a string.
Edit: Clarification on Provided Solutions
The first solution uses the .join() method, which follows this format
<str_to_connect>.join(<iterable_of_str>)
The square brackets used ['Name: ',self.__name, ... self.__title] will pack all your various string arguments into a list. Passing this list into .join() connects it all together into a single str.
The second solution uses the .format() method which follows this format
<str_to_format>.format(<args>...)
You can pass complex formatting into the .format() function, but they generally make use of a {} placeholder, which are then filled with input from the arguments passed.
The essential thing is that both these will return str types.
Further reading: str.join(), PyFormat.
Note: C. Kim's solution in the comments, using %, is also equally valid.
Sorry this is the second post in two days.. I am pulling my hair out with this. I am attempting to take data from reddit and put it into an array in a way I can pull the data out later for tensorflow to parse it. Now the issue is my second object inside of the other object is not giving me whats inside it... "<main.Submission" why am I getting this back?
Goals of this post:
1: Why am I getting <main.Submission> and how should I be doing this.
File "C:/automation/git/tensorflow/untitled0.py", line 35, in <module>
submissions[sm.id].addSubSubmission(Submission.addComment(cmt.id, cmt.author.name, cmt.body))
TypeError: addComment() missing 1 required positional argument: 'body'
Sorry for the long winded and most likely basic questions. Going from powershell to python was not as straight forward as I thought..
Thanks
Cody
import praw
# sets log in data for session
reddit = praw.Reddit(client_id='bY',
client_secret='v9',
user_agent='android:com.example.myredditapp:'
'v1.2.3 (by /u/r)')
class Submission(object):
def __init__(self, id, title, author):
self.id = id
self.title = title
self.subSubmission = {}
self.author = author
def addComment(self, id, author, body):
self.id = id
self.author = author
self.body = body
def addSubSubmission(self,submission):
self.subSubmission[submission,id] = submission
def getSubSubmission(self,id):
return self.subSubmission[id]
submissions = {}
for sm in reddit.subreddit('redditdev').hot(limit=2):
# pulls the ID and makes that the head of each
submissions[sm.id] = Submission(sm.id, sm.title, sm.author.name)
mySubmission = reddit.submission(id=sm.id)
mySubmission.comments.replace_more(limit=0)
# Get all the comments and first post and list their id author and body(comment)
for cmt in mySubmission.comments.list():
submissions[sm.id].addSubSubmission(Submission.addComment(cmt.id, cmt.author.name, cmt.body))
# My trying to read what all there??!? ##
for key in submissions.keys():
value = submissions[key]
print(key, "=", value)
for key, value in submissions.items():
print(key, "=", value)
expecting to see:
{Title = test {comment.id = 1111 {Comment = 'blah', Author = 'Bob'}}
{comment.id = 1112 {Comment = 'blah2', Author = 'Bob2'}}
}
It is giving you back the entire Submission object - but then you're printing it. How should a submission object look on screen when printed? This is something you can define in the Submission class - check out the first answer in this post: Difference between __str__ and __repr__ in Python
To explain this further: python doesn't know how to represent a class on screen. Sure, the class has attributes that are strings, lists, dicts etc, but python knows how to print those. Your class you just created? What's important? What should be printed? python doesn't know this, and is smart enough not to make any assumptions.
If you add a __repr__ function to your class, python will call it and print whatever that function returns.
I have to write a program to demonstrate a customer using their credit card to check out, I have spent a few hours trying to figure out how to do it and have provided my code below.
I have to make a class, then use it in a main function.
This is what I have so far:
class Customer:
def __init__(self, customer_name, credit_card_num, credit_security_code, debit_card_num, debit_pin):
self.customer_name = name
self.credit_card_num = credit_num
self.credit_security_code = credit_code
self.debit_card_num = debit_num
self.debit_pin = debit_pin
def inputCardInfo(self):
self.customer_name = str(input("Enter your name: "))
self.credit_card_num = str(input("Enter credit card Number: "))
self.credit_security_code = str(input("Enter 3-digit security code: "))
self.debit_card_num = str(input("Enter debit card number: "))
self.debit_pin = str(input("Enter 4-digit PIN: "))
then the main function:
from customer import Customer
def main():
print("Welcome to Wake-Mart. Please register.")
customer_name = input("enter name: ")
customer1 = Customer(customer_name)
print("Registration completed")
main()
I don't know the correct way to call the class methods. I feel if I can figure out how to make one of these work I can figure out the rest.
If you want to understand behaviors and properties more deeply I would recommend making a separate behavior for each value. (get_credit_num, get_debit_num, etc.)
Then, in your main, just call each function individually to get each value.
And to clarify, "class functions", or behaviors, are just things an object can do. You call them the same way you would any function, with the only difference being you put the name of the instance you are calling this behavior for before the function to replace "self". So if you were calling "InputCardInfo" for the object customer1, you would do it like so:
customer1.InputCardInfo(other parameters)
Your code as-is will not work because you are not passing all required parameters when initializing your class.
customer1 = Customer(customer_name)
All of the additional parameters besides self included in your def __init__(self, var1, var2, var3): needs to be passed to the class instance when initializing. There are also variable naming issues with your code but I hope my example below clarifies things for you.
A quick note first to help you better understand: self.customer_name = name does not make sense in your code because there is no parameter named name included in the __init__() method. You must associate an instance variable (self.whatever) to a known variable name passed in through the __init__(self, external_var) method so that self.whatever = external_var. Then, and only then, can you use class methods to call self.whatever and expect to receive the data you passed from external_var. Also, additional parameters you include after self in __init__(self, ..., ...) MUST be passed as variables when creating a class instance.
class Customer:
def __init__(self, customer_name, credit_card_num, credit_security_code, debit_card_num, debit_pin):
self.customer_name = customer_name
self.credit_card_num = credit_card_num
self.credit_security_code = credit_security_code
self.debit_card_num = debit_card_num
self.debit_pin = debit_pin
name = 'Mike'
cc_num = '0000 0000 0000 0000'
code = '111'
debit_num = '1111 1111 1111 1111'
pin = '1234'
new_customer = Customer(name, cc_num, code, debit_num, pin)